package com.black.utils.config.loader;

import com.alibaba.fastjson2.JSONObject;
import com.black.utils.file.FileTypeEnum;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * Abstract class for loading configuration data from JSON.
 * 加载JSON格式配置数据的抽象类。
 *
 * @author ylx
 */
public abstract class Loader {

    public static final List<FileTypeEnum> unCheckedTypes = Arrays.asList(FileTypeEnum.PROPERTIES, FileTypeEnum.YAML, FileTypeEnum.YML);

    /**
     * Loads a configuration object from JSON file.
     * 从JSON文件加载配置对象。
     *
     * @param sourcePath The path to the JSON configuration file.
     *                   JSON配置文件的路径。
     * @param target     The class type of the target configuration object.
     *                   目标配置对象的类类型。
     * @param <T>        The type of the target configuration object.
     *                   目标配置对象的类型。
     * @return The loaded configuration object.
     * 加载的配置对象。
     * @throws IOException If an error occurs while loading the JSON file.
     *                     加载JSON文件时发生错误。
     */
    public <T> T loadConfigObject(String sourcePath, Class<T> target) throws IOException {
        JSONObject config = loadJsonConfig(sourcePath);
        return config.toJavaObject(target);
    }

    /**
     * Abstract method to load a JSON configuration object.
     * 加载JSON配置对象的抽象方法。
     *
     * @param sourcePath The configuration file path.
     *                   配置文件的路径。
     * @return The loaded JSON object representing the configuration.
     * 加载的代表配置的JSON对象。
     * @throws IOException If an error occurs while loading the JSON file.
     *                     加载JSON文件时发生错误。
     */
    public abstract JSONObject loadJsonConfig(String sourcePath) throws IOException;

    /**
     * 加载配置文件，识别文件类型并检查。
     *
     * @param sourcePath 配置文件路径
     * @return 配置内容
     * @throws IOException 读取或转化异常
     */
    public final JSONObject load(String sourcePath) throws IOException {
        // 获取loader支持的类型
        List<FileTypeEnum> types = getTypes();
        // 判断文件类型是否再支持范围
        if (types.stream().anyMatch(type -> type.is(sourcePath))) {
            File file = new File(sourcePath);
            // 检查文件存在性
            if (!file.exists() && unCheckedTypes.stream().anyMatch(type -> type.is(sourcePath))) {
                throw new FileNotFoundException(sourcePath);
            }
            return loadJsonConfig(sourcePath);
        }
        throw new IllegalArgumentException("The source file type not supported by this loader");
    }

    /**
     * 获取支持的文件类型
     *
     * @return 支持的文件类型
     */
    public abstract List<FileTypeEnum> getTypes();
}
